﻿using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using LightCAD.Core;
using LightCAD.Core.Element3d;
using LightCAD.Core.Elements;
using LightCAD.MathLib;
using LightCAD.MathLib.Csg;
using LightCAD.Model;
using LightCAD.Runtime;
using LightCAD.Three;
using LightCAD.Three.OpenGL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using static LightCAD.Core.Elements.LcPolyLine;
using static System.Collections.Specialized.BitVector32;

namespace LightCAD.Drawing.Actions
{

    public class SectionAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;
        /// <summary>
        /// 轮廓第一个点
        /// </summary>
        private Vector2? firstPoint { get; set; }
        /// <summary>
        /// 拉伸点
        /// </summary>
        //private Vector2? InsertPoint { get; set; }
        ///// <summary>
        ///// 外轮廓
        ///// </summary>
        //private List<Curve2d> Segments { get; set; }
        /// <summary>
        /// 当前内轮廓
        /// </summary>
        private List<Curve2d> CurInnerSegments { get; set; }
        ///// <summary>
        ///// 内轮廓集合
        ///// </summary>
        //private List<List<Curve2d>> InnerSegmentLists { get; set; }
        /// <summary>
        /// 轮廓命名
        /// </summary>
        private string SectionName = "";
        /// <summary>
        /// 当前绘制轮廓是否是外轮廓
        /// </summary>
        private bool IsOuterLoop = true;
        /// <summary>
        /// 当前绘制线段类型
        /// </summary>
        private string CurrentType = "Line";
        private double SweepAngle = Math.PI;
        private LcSection CurrentSection;
        /// <summary>
        /// 当前圆心画圆曲线
        /// </summary>
        private Arc2d CurrentArc;
        static SectionAction()
        {

            CreateMethods = new LcCreateMethod[3];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "CreateSection",
                Description = "创建外轮廓",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "指定起点:" },
                    new LcCreateStep { Name=  "Step1", Options= "下一个点或[圆弧(A)/放弃(U)]:" },
                    new LcCreateStep { Name=  "Step2", Options= "下一个点或[圆弧(A)/闭合(C)/放弃(U)/]:" },
                    new LcCreateStep { Name=  "Step3", Options= "[角度(A)/圆心(CE)/半径(R)/第二个点(S)/直线(L)/放弃(U)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "[角度(A)/圆心(CE)/闭合(CL)/直线(L)/半径(R)/第二个点(S)/放弃(U)]:" },
                    new LcCreateStep { Name=  "Step5", Options= "指定圆弧的圆心:" },
                    new LcCreateStep { Name=  "Step6", Options= "指定圆弧的端点或 [角度(A)/长度(L)/切换方向(C)/]:" },
                    new LcCreateStep { Name=  "Step7", Options= "指定夹角:" },
                    new LcCreateStep {Name="Step8",Options="指定圆弧的端点(按住 Ctrl 键以切换方向)或 [圆心(CE)/半径(R)]:"}
                }
            };
            CreateMethods[1] = new LcCreateMethod()
            {
                Name = "CreateInnerSection",
                Description = "创建内轮廓",
                Steps = new LcCreateStep[]
              {
                    new LcCreateStep { Name=  "Next", Options= "[创建内轮廓(N)/创建完成(O):" },
                    new LcCreateStep { Name=  "InsertPoint", Options= "指定拉伸点:" },
                    new LcCreateStep { Name=  "Name", Options= "命名轮廓:" },
              }
            };

        }




        internal static void Initilize()
        {
            ElementActions.Section = new SectionAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Section, ElementActions.Section);

        }

        private InElementsInputer InElementsInputer { get; set; }
        private ElementSetInputer ElementInputers { get; set; }
        private ElementInputer ElementInputer { get; set; }
        private CmdTextInputer CmdTextInputer { get; set; }
        private PointInputer PointInputer { get; set; }



        private SectionAction() { }
        public SectionAction(IDocumentEditor docEditor,string command) : base(docEditor)
        {
            this.commandCtrl.WriteInfo($"命令：{command}");
        }

        public void ExecEdit(string[] args)
        {
            this.StartCreating();
            StartSectionEditing();
            this.PointInputer = new PointInputer(this.docEditor);
            var win = (ISectionWindow)AppRuntime.UISystem.CreateWindow("SectionsForm");
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result != LcDialogResult.OK)
            {
                return;
            }
            if (!SectionManager.Sections.TryGetValue(win.SectionId, out var section))
                return;
            //this.StartCreating();

            //CurrentSection.Segments = new List<Curve2d>();
            //this.InnerSegmentLists = new List<List<Curve2d>>();

            //this.vportRt.SectionEditingObject = new SectionEditingObject()
            //{
            //    Target = section
            //};
            //this.vportRt.SectionEditingObject.Initilize(this.docRt.Document);
            //this.vportRt.StartSectionEditing();
            this.vportRt.SectionEditingObject.Target = section;
            this.vportRt.ActiveElementSet.InsertElement(section);
            this.EndCreating();
            //this.vportRt.CloseSectionEditing();
        }
        public async void ExecEndEdit(string[] args)
        {
            this.EndCreating();
            this.vportRt.CloseSectionEditing();
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            StartSectionEditing();
            this.vportRt.ActiveElementSet.InsertElement(CurrentSection);
            var curMethod = CreateMethods[0];
            this.PointInputer = new PointInputer(this.docEditor);
            IsOuterLoop = true;
            var succes = await Creating(curMethod, CurrentSection.Segments);
            if (succes)
            {
                var nextMethod = CreateMethods[1];
                do
                {
                    IsOuterLoop = false;
                    this.firstPoint = null;
                    var result0 = await PointInputer.Execute(nextMethod.Steps[0].Options);
                    if (PointInputer.isCancelled)
                    {
                        goto End;
                    }
                    else if (!string.IsNullOrEmpty(result0.Option))
                    {
                        if (result0.Option.ToUpper() == "N")
                        {
                            CurInnerSegments = new List<Curve2d>();
                            CurrentSection.InnerSegments.Add(CurInnerSegments);
                            succes = await Creating(curMethod, CurInnerSegments);
                            if (!succes)
                            {
                                goto End;
                            } 
                        }
                        else if (result0.Option.ToUpper() == "O")
                        {
                            break;
                        }
                    }
                } while (true);
                //BasePoint:
                //var result1 = await PointInputer.Execute(nextMethod.Steps[1].Options);
                //if (PointInputer.isCancelled)
                //{
                //    goto End;
                //}
                //else
                //{
                //    if (result1.ValueX != null)
                //    {
                //        this.InsertPoint = (Vector2) result1.ValueX;
                //    }
                //    else
                //    {
                //        goto BasePoint;
                //    }
                //}

                do
                {
                    var result2 = await PointInputer.Execute(nextMethod.Steps[2].Options);
                    if (PointInputer.isCancelled)
                    {
                        goto End;
                    }
                    else
                    {
                        if (result2.Option!=null&& result2.Option.Trim()!="")
                        {
                            this.SectionName = result2.Option.Trim();
                            if (SectionManager.Sections.ContainsKey(this.SectionName))
                            {
                                PointInputer.Prompt("命名重复！");
                                continue;
                            }
                            break;
                        }
                    }
                } while (true);
                CreateSection();
            }
        End:
            
            CurInnerSegments = null;
            CurrentSection = null;
            CurrentArc = null;
            this.PointInputer = null;
            this.vportRt.CloseSectionEditing();
            this.Cancel();
            this.EndCreating();
        }
        private void StartSectionEditing()
        {
            CurrentSection = new LcSection();
            CurrentSection.Segments = new List<Curve2d>();
            CurrentSection.InnerSegments = new List<List<Curve2d>>();
            this.vportRt.SectionEditingObject = new SectionEditingObject() { };
            this.vportRt.SectionEditingObject.Initilize(this.docRt.Document);
            this.vportRt.StartSectionEditing();
        }
        private Vector2 GetOptionVector(string Option)
        {
            if (!string.IsNullOrEmpty( Option))
            {
                var xyz =  Option.split(",");
                if (double.TryParse(xyz[0].Trim(), out var pX) && double.TryParse(xyz[1].Trim(), out var pY))
                {
                    return new Vector2(pX,pY);
                }
            }
            return null;
        }
        private async Task<bool> Creating(LcCreateMethod curMethod, List<Curve2d> curSg )
        {
        Step0:
            this.CurrentType = "Line";
            var step0 = curMethod.Steps[0];
            var result0 = await PointInputer.Execute(step0.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result0.ValueX!=null)
            {
                this.firstPoint = (Vector2)result0.ValueX;
            }
            else
            {
                this.firstPoint = GetOptionVector(result0.Option);
                if (firstPoint==null)
                    goto Step0;
            }
        Step1:
            this.CurrentType = "Line";
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
        Step1ValueX:
            if (result1.ValueX != null)
            {
                Vector2 pointB = (Vector2)result1.ValueX;
                Line2d pline = new Line2d();
                if (curSg.Count > 0)
                {
                    var lastLine = curSg.Last();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    pline.Start = endPoint.Clone();
                }
                else
                {
                    pline.Start = this.firstPoint.Clone();
                }
                pline.End = pointB.Clone();
                curSg.Add(pline);
                if (curSg.Count > 1)
                {
                    goto Step2;
                }
                goto Step1;
            }
            else
            if (result1.Option != null)
            {
                var opvec = GetOptionVector(result1.Option);
                if (opvec!=null)
                {
                    result1.ValueX = opvec;
                    goto Step1ValueX;
                }
                if (result1.Option.ToUpper() == "A")
                {
                    goto Step3;
                }
                else
                {
                    goto Step1;
                }
            }
            goto Step1;
        Step2:
            this.CurrentType = "Line";
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                return false; 
            }
        Step2ValueX:
            if (result2.ValueX != null)
            {
                Vector2 pointB = (Vector2)result2.ValueX;
                Line2d pline = new Line2d();
                var lastLine = curSg.Last();
                var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                pline.Start = endPoint.Clone();
                pline.End = pointB.Clone();
                curSg.Add(pline);
                if (Utils.Vec2EQ(curSg.Last().GetPoints(1).Last(), curSg.First().GetPoints(1).First(), 0.001))
                {
                    return true;
                }
                goto Step2;
            }
            else
            if (result2.Option != null)
            {
                var opvec = GetOptionVector(result2.Option);
                if (opvec != null)
                {
                    result2.ValueX = opvec;
                    goto Step2ValueX;
                }
                if (result2.Option.ToUpper() == "A")
                {
                    if (curSg.Count >= 2 || curSg.Any(n => n is Arc2d))
                        goto Step4;
                    else
                        goto Step3;
                }
                else if (result2.Option.ToUpper() == "C")
                {
                    Line2d pline = new Line2d();
                    var lastLine = curSg.Last();
                    var first = curSg.First();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    var startPoint = first is Line2d ? (first as Line2d).Start : (first as Arc2d).GetPoints(1).First();
                    pline.Start = endPoint.Clone();
                    pline.End = startPoint.Clone();
                    curSg.Add(pline);
                    return true;
                }
            }
            goto Step2;
        Step3:
            this.CurrentType = "Arc";
            var step3 = curMethod.Steps[3];
            var result3 = await PointInputer.Execute(step3.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
        Step3ValueX:
            if (result3.ValueX != null)
            {
                Vector2 currP = (Vector2)result3.ValueX;
                Vector2 lastStart, lastEnd;
                if (curSg.Count > 0)
                {
                    if (curSg.Last() is Line2d lastline)
                    {
                        lastEnd = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = curSg.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        lastEnd = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                }
                else
                {
                    lastStart = new(this.firstPoint.X - 5, this.firstPoint.Y);
                    lastEnd = this.firstPoint.Clone();
                }

                var cir = GetCircleBylinePoint(lastStart, lastEnd, currP);
                if (cir == null)
                {
                    Line2d line = new Line2d();
                    line.Start = lastEnd;
                    line.End = currP;
                    curSg.Add(line);
                    if (Utils.Vec2EQ(curSg.Last().GetPoints(1).Last(), curSg.First().GetPoints(1).First(), 0.001))
                    {
                        return true;
                    }
                    goto Step3;
                }
                else
                {
                    var arc = new Arc2d();
                    arc.Center = cir.Item1;
                    arc.Radius = Vector2.Distance(cir.Item1, currP);
                    var angle = currP.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                    arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                    arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                    arc.EndAngle = currP.Clone().Sub(arc.Center).Angle();
                    if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                    {
                        if (curSg.Count > 1)
                        {
                            goto Step4;
                        }
                        else
                        {
                            goto Step3;
                        }
                    }
                    curSg.Add(arc);
                    if (Utils.Vec2EQ(curSg.Last().GetPoints(1).Last(), curSg.First().GetPoints(1).First(), 0.001))
                    {
                        return true;
                    }
                    goto Step4;
                }
            }
            else if (result3.Option != null)
            {
                var opvec = GetOptionVector(result3.Option);
                if (opvec != null)
                {
                    result3.ValueX = opvec;
                    goto Step3ValueX;
                }
                if (result3.Option.ToUpper() == "L")
                {
                    goto Step1;
                }
                else if (result3.Option.ToUpper() == "CE")
                {
                    goto Step5;
                }
                else if (result3.Option.ToUpper() == "A")
                {
                    goto Step7;
                }
            }
            goto Step3;
        Step4:
            this.CurrentType = "Arc";
            var step4 = curMethod.Steps[4];
            var result4 = await PointInputer.Execute(step4.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
        Step4ValueX:
            if (result4.ValueX != null)
            {
                Vector2 currP = (Vector2)result4.ValueX;
                Vector2 lastEnd, lastStart;
                if (curSg.Last() is Line2d lastline)
                {
                    lastEnd = lastline.End.Clone();
                    lastStart = lastline.Start.Clone();
                }
                else
                {
                    var arc = curSg.Last() as Arc2d;
                    var arcp = arc.GetPoints(100);
                    lastEnd = arcp.Last().Clone();
                    lastStart = arcp[98].Clone();
                }

                var cir = GetCircleBylinePoint(lastStart, lastEnd, currP);
                if (cir == null)
                {
                    Line2d line = new Line2d();
                    line.Start = lastEnd;
                    line.End = currP;
                    curSg.Add(line);
                    if (Utils.Vec2EQ(curSg.Last().GetPoints(1).Last(), curSg.First().GetPoints(1).First(), 0.001))
                    {
                        return true;
                    }
                }
                else
                {
                    var arc = new Arc2d();
                    arc.Center = cir.Item1;
                    //arc.Angle = cir.Item3;
                    arc.Radius = Vector2.Distance(cir.Item1, currP);
                    var angle = currP.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                    arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                    arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                    arc.EndAngle = currP.Clone().Sub(arc.Center).Angle();
                    if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                    {
                        goto Step4;
                    }
                    curSg.Add(arc);
                }
                if ( Utils.Vec2EQ( curSg.Last().GetPoints(1).Last(),curSg.First().GetPoints(1).First(),0.001))
                {
                    return true;
                }
                goto Step4;

            }
            else if (result4.Option != null)
            {
                var opvec = GetOptionVector(result4.Option);
                if (opvec != null)
                {
                    result4.ValueX = opvec;
                    goto Step4ValueX;
                }
                if (result4.Option.ToUpper() == "L")
                {
                    goto Step2;
                }
                else if (result4.Option.ToUpper() == "CL")
                {
                    Vector2 lastStart, lastEnd;
                    var firstLine = curSg.First();
                    if (curSg.Last() is Line2d lastline)
                    {
                        lastEnd = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = curSg.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        lastEnd = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                    var fsp = (firstLine is Line2d ? (firstLine as Line2d).Start : (firstLine as Arc2d).GetPoints(1).First()).Clone();
                    //Line2d line = new Line2d();
                    //line.Start = lep.Clone();
                    //line.End = fsp.Clone();
                    var cir = GetCircleBylinePoint(lastStart, lastEnd, fsp );
                    if (cir == null)
                    {
                        Line2d line = new Line2d();
                        line.Start = lastEnd;
                        line.End = fsp;
                        curSg.Add(line);
                    }
                    else
                    {
                        var arc = new Arc2d();
                        arc.Center = cir.Item1;
                        //arc.Angle = cir.Item3;
                        arc.Radius = Vector2.Distance(cir.Item1, fsp);
                        var angle = fsp.Clone().Sub(lastEnd).Angle() - lastStart.Clone().Sub(lastEnd).Angle();
                        arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                        arc.StartAngle = lastEnd.Clone().Sub(arc.Center).Angle();
                        arc.EndAngle = fsp.Clone().Sub(arc.Center).Angle();
                        if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                        {
                            goto Step4;
                        }
                        curSg.Add(arc);
                    }
                    return true;
                }
                else if (result4.Option.ToUpper() == "CE")
                {
                    goto Step5;
                }
                else if (result4.Option.ToUpper() == "A")
                {
                    goto Step7;
                }
            }
            goto Step4;
        Step5:
            this.CurrentType = "Arc-CE";
            var step5 = curMethod.Steps[5];
            var result5 = await PointInputer.Execute(step5.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
        Step5ValueX:
            if (result5.ValueX != null)
            {
                CurrentArc = new Arc2d();
                Vector2 center = (Vector2)result5.ValueX;
                CurrentArc.Center = center.Clone();
                Vector2 lastEnd;
                if (curSg.Count > 0)
                {
                    var lastLine = curSg.Last();
                    var endPoint = lastLine is Line2d ? (lastLine as Line2d).End : (lastLine as Arc2d).GetPoints(1).Last();
                    lastEnd = endPoint.Clone();
                }
                else
                {
                    lastEnd = this.firstPoint.Clone();
                }
                CurrentArc.Radius = center.DistanceTo(lastEnd);
                CurrentArc.StartAngle = lastEnd.Clone().Sub(center).Angle();
                goto Step6;
            }
            else
            {
                var opvec = GetOptionVector(result5.Option);
                if (opvec != null)
                {
                    result5.ValueX = opvec;
                    goto Step5ValueX;
                }
            }
            goto Step5;
        Step6:
            var step6 = curMethod.Steps[6];
            var result6 = await PointInputer.Execute(step6.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
        Step6ValueX:
            if (result6.ValueX != null)
            {
                Vector2 end = (Vector2)result6.ValueX;
                CurrentArc.EndAngle = end.Clone().Sub(CurrentArc.Center).Angle();
                curSg.Add(CurrentArc.Clone());
                if (Utils.Vec2EQ(curSg.Last().GetPoints(1).Last(), curSg.First().GetPoints(1).First(), 0.001))
                {
                    return true;
                }
                CurrentArc = null;
                goto Step4;
            }
            else if (result6.Option != null)
            {
                var opvec = GetOptionVector(result6.Option);
                if (opvec != null)
                {
                    result6.ValueX = opvec;
                    goto Step6ValueX;
                }
                if (result6.Option.ToUpper() == "C")
                {
                    CurrentArc.IsClockwise = !CurrentArc.IsClockwise;
                }
            }
            goto Step6;
        Step7:
            CurrentType = "Arc-Angel";
            var step7 = curMethod.Steps[7];
            var result7 = await PointInputer.Execute(step7.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            if (result7.Option != null && double.TryParse(result7.Option.Trim(),out var sweepAngle))
            {
                this.SweepAngle = sweepAngle;
            }
            goto Step7;
        Step8:
            CurrentType = "Arc-Angel";
            var step8 = curMethod.Steps[8];
            var result8= await PointInputer.Execute(step8.Options);
            if (PointInputer.isCancelled)
            {
                return false;
            }
            
            goto Step8;
        }

        public List<Curve2d> Cursor = new List<Curve2d>() {
new Line2d(new Vector2(20, 20), new Vector2(-20, 20)),
new Line2d(new Vector2(-20, 20), new Vector2(-20, -20)),
new Line2d(new Vector2(-20, -20), new Vector2(20, -20)),
new Line2d(new Vector2(20, -20), new Vector2(20, 20)),
new Line2d(new Vector2(10, 10), new Vector2(-10, 10)),
new Line2d(new Vector2(-10, 10), new Vector2(-10, -10)),
new Line2d(new Vector2(-10, -10), new Vector2(10, -10)),
new Line2d(new Vector2(10, -10), new Vector2(10, 10)),
new Line2d(new Vector2(50,0),new Vector2(-50,0)),new Line2d(new Vector2(0,50),new Vector2(0,-50)) };

        private void DrawCursor(SKCanvas canvas, Vector2 wcs_mp)
        {
            var cursor = this.Cursor.Clone();
            foreach (var curve in cursor)
            {
                if (curve is Line2d line)
                {
                    line.Start.MultiplyScalar(1 / this.vportRt.Viewport.Scale);
                    line.End.MultiplyScalar(1 / this.vportRt.Viewport.Scale);
                    line.Translate(wcs_mp);
                    var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                    using (var elePen = new SKPaint { Color = SKColors.White, IsStroke = true })
                    {
                        canvas.DrawLine(start, end, elePen);
                    }
                }
                else if (curve is Arc2d arc)
                {
                    arc.Radius *= (1 / this.vportRt.Viewport.Scale);
                    arc.Translate(wcs_mp);
                    using (var elePen = new SKPaint { Color = SKColors.White, IsStroke = true })
                    {
                        Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                        this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                    }
                }
            }
        }
        public override SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var section = element as LcSection;
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { Element = element };
            if (sscur.ObjectOn&& section.Segments.Count>0)
            {
                var firstP = section.Segments.First().GetPoints(0).First().Clone();
                if (Utils.Vec2EQ(firstP, point, maxDistance))
                {
                    result.Point = firstP;
                    result.Name = "Start";
                    result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, section.Segments.First().Clone()));
                }
                if (section.InnerSegments.Count>0&& section.InnerSegments.Last().Count>0)
                {
                    var innerFirst= section.InnerSegments.Last().First().GetPoints(0).First().Clone();
                    if (Utils.Vec2EQ(innerFirst, point, maxDistance))
                    {
                        result.Point = innerFirst;
                        result.Name = "Start";
                        result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, section.InnerSegments.Last().First().Clone()));
                    }
                }
            }
            if (result.Point != null)
                return result;
            else
                return null;
        }
        private void CreateSection()
        {
            if (CurrentSection.Segments == null || (CurrentSection.Segments.Count < 3 && !CurrentSection.Segments.Any(n => n is Arc2d)))
            {
                // 如果线段列表为空或线段数量小于3且不包含任何弧线，则无法创建闭合轮廓
                return;
            }
            DocumentManager.CurrentRecorder.BeginAction("SECTION");
            var doc = this.docRt.Document;
            //var section = doc.CreateObject<LcSection>();
            var isClockWise = ShapeUtils.isClockWise(CurrentSection.Segments.SelectMany(n => n.GetPoints((n is Arc2d ? 32 : 1))).ToListEx());
            var newShape = new List<Curve2d>();
           // var offset = this.InsertPoint.Clone().Negate();
            for (var i = CurrentSection.Segments.Count() - 1; i >= 0; i--)
            {
                var cur = CurrentSection.Segments[i];
                //cur.Translate(offset);
                if (isClockWise)
                {
                    cur.Reverse();
                    newShape.Add(cur.Clone());
                }
            }
            if (isClockWise)
                CurrentSection.Segments = newShape;
            for (var k =0;k< CurrentSection.InnerSegments.Count;k++)
            {
                isClockWise = ShapeUtils.isClockWise(CurrentSection.InnerSegments[k].SelectMany(n => n.GetPoints((n is Arc2d ? 32 : 1))).ToListEx());
                var newInnerShape = new List<Curve2d>();
                for (var i = CurrentSection.InnerSegments[k].Count() - 1; i >= 0; i--)
                {
                    var cur = CurrentSection.InnerSegments[k][i];
                    //cur.Translate(offset);
                    if (!isClockWise)
                    {
                        cur.Reverse();
                        newInnerShape.Add(cur.Clone());
                    }
                }
                if (!isClockWise)
                    CurrentSection.InnerSegments[k] = newInnerShape;
            }
            CurrentSection.Name = this.SectionName;
            CurrentSection.Uuid = Guid.NewGuid().ToString();
            //section.Segments = Segments;
            //section.InnerSegments = InnerSegmentLists;
            CurrentSection.ResetBoundingBox();
            SectionManager.Sections.Add(CurrentSection.Uuid, CurrentSection);
            //this.vportRt.SectionEditingObject.Target = section;
            //var curve3ds = section.Segments.Select(n =>
            //{
            //    Curve3d curve;
            //    if (n is Line2d line)
            //    {
            //        curve = new Line3d(line.Start.ToVector3(), line.End.ToVector3());
            //    }
            //    else
            //    {
            //        var arc = n as Arc2d;
            //        curve = new Arc3d(arc.Center.ToVector3(), arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsClockwise);
            //    }
            //    return curve;
            //}).ToList();
            //var inCurve3ds = section.InnerSegments.Select(m => m.Select(n =>
            //{
            //    Curve3d curve;
            //    if (n is Line2d line)
            //    {
            //        curve = new Line3d(line.Start.ToVector3(), line.End.ToVector3());
            //    }
            //    else
            //    {
            //        var arc = n as Arc2d;
            //        curve = new Arc3d(arc.Center.ToVector3(), arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsClockwise);
            //    }
            //    return curve;
            //}).ToList());
            //var profile = new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), curve3ds);
            //profile.InnerLoops.AddRange(inCurve3ds);
            //var mats = new LcMaterial[3]
            //{
            //    new LcMaterial() { Color = new Color(0xff0000) },
            //    new LcMaterial() { Color = new Color(0x00ff00) },
            //    new LcMaterial() { Color = new Color(0x0000ff) }
            //};
            //var Extrude = new LcExtrude(profile, 2000, mats);
            //Extrude.Initilize(this.docRt.Model3DEditRt.DocRt.Document);
            //Extrude.UpdateMatrix();
            //var extrudeAction = new Extrude3dAction(this.docRt.Model3DEditRt);
            //Extrude.Rt3DAction = extrudeAction;
            //this.docRt.Document.ModelSpace.InsertElement(Extrude);
            //this.docRt.Action.ClearSelects();

            DocumentManager.CurrentRecorder.EndAction();



        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
        public override void CreateElement(LcElement element, Matrix3 matrix)
        {
            var grp = element as LcGroup;
            foreach (var ele in grp.Elements)
            {
                var eleAction = (ele.RtAction as ElementAction);
                eleAction.CreateElement(ele, matrix);
            }
        }
        public override void CreateElement(LcElement element, Vector2 basePoint, double scaleFactor)
        {
            var grp = element as LcGroup;
            foreach (var ele in grp.Elements)
            {
                var eleAction = (ele.RtAction as ElementAction);
                eleAction.CreateElement(ele, basePoint, scaleFactor);
            }

        }
        private bool CheckIntersect(Curve2d pline, Curve2d nextLine)
        {
            return true;
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var section = element as LcSection;
            var pen = this.GetDrawPen(section);
            for (int i = 0; i < section.Segments.Count; i++)
            {
                var curve = section.Segments[i];
                if (curve is Line2d curLine)
                {
                    var mstart = curLine.Start;
                    var mend = curLine.End;
                    var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

                    if (pen == Constants.defaultPen)
                    {
                        //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                        using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                        {
                            canvas.DrawLine(start, end, elePen);
                        }
                    }
                    else
                    {
                        canvas.DrawLine(start, end, pen);
                    }
                }else if (curve is Arc2d arc)
                {
                    if (pen == Constants.defaultPen)
                    {
                        //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                        using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                        {
                            this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        }
                    }
                    else
                    {
                        this.vportRt.DrawArc(arc, matrix, canvas, pen);
                    }

                }

            }
            foreach (var innerSg in section.InnerSegments)
            {
                for (int i = 0; i < innerSg.Count; i++)
                {
                    var curve = innerSg[i];
                    if (curve is Line2d curLine)
                    {
                        var mstart = curLine.Start;
                        var mend = curLine.End;
                        var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
                        var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

                        if (pen == Constants.defaultPen)
                        {
                            //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                            using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                            {
                                canvas.DrawLine(start, end, elePen);
                            }
                        }
                        else
                        {
                            canvas.DrawLine(start, end, pen);
                        }
                    }
                    else if (curve is Arc2d arc)
                    {
                        if (pen == Constants.defaultPen)
                        {
                            //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                            using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                            {
                                this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                            }
                        }
                        else
                        {
                            this.vportRt.DrawArc(arc, matrix, canvas, pen);
                        }

                    }

                }

            }
        }
        public override void DrawTemp(SKCanvas canvas)
        {
           
        }
        public override void DrawAuxLines(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var sk_p = this.vportRt.ConvertWcsToScr(wcs_mp).ToSKPoint();
            DrawCursor(canvas,wcs_mp);
            foreach (var ele in CurrentSection.Segments)
            {
                if (ele is Line2d line)
                {
                    var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                    var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                    using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                    {
                        canvas.DrawLine(start, end, elePen);
                    }
                }
                else if (ele is Arc2d arc)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                    {
                        Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                        this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                    }
                }
            }
            foreach (var inners in CurrentSection.InnerSegments)
            {
                foreach (var ele in inners)
                {
                    if (ele is Line2d line)
                    {
                        var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                        var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                        using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                        {
                            canvas.DrawLine(start, end, elePen);
                        }
                    }
                    else if (ele is Arc2d arc)
                    {
                        using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                        {
                            Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                            this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        }
                    }
                }
            }
            Vector2 startpoint = new Vector2(0, 0);//上一个元素的开始点
            Vector2 lastStart;
            if (this.firstPoint == null)
                return;
            if (IsOuterLoop)
            {
                if (CurrentSection.Segments.Count == 0)
                {
                    startpoint = this.firstPoint.Clone();
                    lastStart = new Vector2(this.firstPoint.X - 5, this.firstPoint.Y);
                }
                else
                {
                    if (CurrentSection.Segments.Last() is Line2d lastline)
                    {
                        startpoint = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = CurrentSection.Segments.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        startpoint = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                }
            }
            else
            {
                if (CurInnerSegments.Count == 0)
                {
                    startpoint = this.firstPoint.Clone();
                    lastStart = new Vector2(this.firstPoint.X - 5, this.firstPoint.Y);
                }
                else
                {
                    foreach (var ele in this.CurInnerSegments)
                    {
                        if (ele is Line2d line)
                        {
                            var start = this.vportRt.ConvertWcsToScr(line.Start).ToSKPoint();
                            var end = this.vportRt.ConvertWcsToScr(line.End).ToSKPoint();
                            using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                            {
                                canvas.DrawLine(start, end, elePen);
                            }
                        }
                        else if (ele is Arc2d arc)
                        {
                            using (var elePen = new SKPaint { Color = SKColors.Green, IsStroke = true })
                            {
                                Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                                this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                            }
                        }
                    }
                    if (CurInnerSegments.Last() is Line2d lastline)
                    {
                        startpoint = lastline.End.Clone();
                        lastStart = lastline.Start.Clone();
                    }
                    else
                    {
                        var arc = CurInnerSegments.Last() as Arc2d;
                        var arcp = arc.GetPoints(100);
                        startpoint = arcp.Last().Clone();
                        lastStart = arcp[98].Clone();
                    }
                }
            }
            if (CurrentType == "Arc")
            {
                var cir = GetCircleBylinePoint(lastStart, startpoint, wcs_mp);
                if (cir == null)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                    }
                    return;
                }
                var arc = new Arc2d();
                arc.Center = cir.Item1.Clone();
                arc.Radius = startpoint.DistanceTo(arc.Center);
                var angle = wcs_mp.Clone().Sub(startpoint).Angle() - lastStart.Clone().Sub(startpoint).Angle();
                arc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
                arc.StartAngle = startpoint.Clone().Sub(arc.Center).Angle();
                arc.EndAngle = wcs_mp.Clone().Sub(arc.Center).Angle();
                if (double.IsNaN(arc.StartAngle) || double.IsNaN(arc.EndAngle))
                {
                    return;
                }
                using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                {
                    //arc.EndAngle = wcs_mp.Sub(arc.Center).Angle();
                    //var lcenter = this.vportRt.ConvertWcsToScr(arc.Center).ToSKPoint();
                    //double lradius = Math.Sqrt(Math.Pow(lcenter.X - sk_p.X, 2) + Math.Pow(lcenter.Y - sk_p.Y, 2));
                    //float lx1 = (float)(lcenter.X - lradius);
                    //float ly1 = (float)(lcenter.Y - lradius);
                    //float lx2 = (float)(lcenter.X + lradius);
                    //float ly2 = (float)(lcenter.Y + lradius);
                    Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                    this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                }
                using (var elePen = new SKPaint { Color = SKColors.Yellow, IsStroke = true, PathEffect = SKPathEffect.CreateDash(new float[] { 10, 10, 30, 10 }, 0) })
                {
                    canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                }
            }
            else if (CurrentType == "Arc-CE") {
                if (CurrentArc==null)
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                    }
                }
                else
                {
                    using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                    {
                        Matrix3 matrix = Matrix3.GetTranslate(new Vector2(0, 0));
                        var arc = CurrentArc.Clone() as Arc2d;
                        arc.EndAngle = wcs_mp.Sub(arc.Center).Angle();
                        this.vportRt.DrawArc(arc, matrix, canvas, elePen);
                        //var lcenter =  this.vportRt.ConvertWcsToScr(arc.Center).ToSKPoint();
                        //double lradius = Math.Sqrt(Math.Pow(lcenter.X - sk_p.X, 2) + Math.Pow(lcenter.Y - sk_p.Y, 2));
                        //float lx1 = (float)(lcenter.X - lradius);
                        //float ly1 = (float)(lcenter.Y - lradius);
                        //float lx2 = (float)(lcenter.X + lradius);
                        //float ly2 = (float)(lcenter.Y + lradius);
                        //SKRect lskrect = new SKRect(lx1, ly1, lx2, ly2);
                        //canvas.DrawArc(lskrect,(float)arc.StartAngle, (float)arc.EndAngle,false,elePen);
                    }
                }
            }
            else {
                
                using (var elePen = new SKPaint { Color = SKColors.Gray, IsStroke = true })
                {
                    canvas.DrawLine(this.vportRt.ConvertWcsToScr(startpoint).ToSKPoint(), sk_p, elePen);
                }
            }
        }
        private string _gripName;
        private Vector2 _position;
        private LcSection _section;
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var section = element as LcSection; //getHel
            var grips = new List<ControlGrip>();
            for(var i=0;i< section.Segments.Count;i++)
            {
                var curve = section.Segments[i];
                var points = curve.GetPoints(2);
                grips.Add(new ControlGrip()
                {
                    Element = section,
                    Name = "SecGrip_Start_" + i,
                    Position = points[0].Clone()
                });
                grips.Add(new ControlGrip()
                {
                    Element = section,
                    Name = "SecGrip_Center_" + i,
                    Position = points[1].Clone()
                });                
            }
            for (var k = 0; k < section.InnerSegments.Count; k++)
            {
                var curves = section.InnerSegments[k];
                for(var i=0;i<curves.Count;i++)
                {
                    var curve = curves[i];
                    var points = curve.GetPoints(2);
                    grips.Add(new ControlGrip()
                    {
                        Element = section,
                        Name = "SecInnerGrip_Start_" + k + "_" + i,
                        Position = points[0].Clone()
                    });
                    grips.Add(new ControlGrip()
                    {
                        Element = section,
                        Name = "SecInnerGrip_Center_" + k + "_" + i,
                        Position = points[1].Clone()
                    });
                }               
            }
            return grips.ToArray();
        }
        private void UpdateArc2dByPoints(ref Arc2d curArc, Vector2 start,Vector2 mdi,Vector2 end)
        {
            var center = GetCircleCenter(mdi, start, end);
            var radius = center.DistanceTo(mdi);
            var startAngle = start.Clone().Sub(center).Angle();
            var endAngle = end.Clone().Sub(center).Angle();
            var mdiAngle = mdi.Clone().Sub(start).Angle();
            var lastAngle = end.Clone().Sub(start).Angle();
            var angle = mdiAngle - lastAngle;
            curArc.IsClockwise = angle < -Math.PI || (angle > 0 && angle < Math.PI);
            curArc.Radius = radius;
            curArc.StartAngle = startAngle;
            curArc.EndAngle = endAngle;
            curArc.Center = center;
        }
        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            if (!isEnd)
            {
                var current = element as LcSection;
                if (_section==null) 
                {
                    _section = current.Clone() as LcSection;
                }
                _gripName = gripName;
                _position = position;
                var type = gripName.Substring(0,gripName.IndexOf("_"));
                var grips = gripName.split("_");
                if (grips.Contains("SecGrip"))
                {
                    var index = int.Parse(grips[2]);
                    var curve = _section.Segments[index];
                    var curCurve = current.Segments[index];
                    UpdateSegment(curve,curCurve,current.Segments,_section.Segments,position,index,grips);
                }
                else
                {
                    var index = int.Parse(grips[3]);
                    var innerIndex = int.Parse(grips[2]);
                    var curve = _section.InnerSegments[innerIndex][index];
                    var curCurve = current.InnerSegments[innerIndex][index];
                    UpdateSegment(curve, curCurve, current.InnerSegments[innerIndex],_section.InnerSegments[innerIndex], position, index, grips);
                }
            }
            else
            {
                _section = null;
            }
        }
        /// <summary>
        /// 更新当前轮廓
        /// </summary>
        /// <param name="curve">复制记录移动之前的线段</param>
        /// <param name="curCurve">当前线段</param>
        /// <param name="current">当前轮廓</param>
        /// <param name="copy">复制的轮廓</param>
        /// <param name="position"></param>
        /// <param name="index"></param>
        /// <param name="grips"></param>
        private void UpdateSegment(Curve2d curve,Curve2d curCurve,List<Curve2d> current, List<Curve2d> copy, Vector2 position,int index,List<string> grips)
        {
            if (grips.Contains("Center"))
            {
                if (curve is Arc2d)
                {
                    var curArc = curCurve as Arc2d;
                    var points = curve.GetPoints(2);
                    UpdateArc2dByPoints(ref curArc, points[0], position.Clone(), points[2]);
                }
                else
                {
                    //var line = curve as Line2d;
                    var curLine = curCurve as Line2d;
                    var offset = position.Clone().Sub(curLine.GetPoints(2)[1]);
                    curLine.Translate(offset);
                    Curve2d curLast = index == 0 ? current.Last() : current[index - 1];
                    Curve2d curLastCopy = index == 0 ? copy.Last() : copy[index - 1];
                    Curve2d curNext = index == current.Count - 1 ? current.First() : current[index + 1];
                    Curve2d curNextCopy = index == current.Count - 1 ? copy.First() : copy[index + 1];

                    //当轮廓线数量为2时，另一条线必定为曲线
                    if (current.Count == 2)
                    {
                        var curLastArc = curLast as Arc2d;
                        var newMdi = curLastCopy.GetPoints(2)[1];
                        UpdateArc2dByPoints(ref curLastArc, curLine.End.Clone(), newMdi, curLine.Start.Clone());
                    }
                    else
                    {
                        if (curLast is Arc2d curLastArc)
                        {
                            var points = curLastCopy.GetPoints(2);
                            UpdateArc2dByPoints(ref curLastArc, points[0], points[1], curLine.Start.Clone());
                        }
                        else if (curLast is Line2d curLastLine)
                        {
                            curLastLine.End = curLine.Start.Clone();
                        }
                        if (curNext is Arc2d curNextArc)
                        {
                            var points = curNextCopy.GetPoints(2);
                            UpdateArc2dByPoints(ref curNextArc, curLine.End.Clone(), points[1], points[2]);
                        }
                        else if (curNext is Line2d curNextLine)
                        {
                            curNextLine.Start = curLine.End.Clone();
                        }
                    }
                }
            }
            else
            {
                if (curve is Arc2d)
                {
                    var curArc = curCurve as Arc2d;
                    var points = curve.GetPoints(2);
                    UpdateArc2dByPoints(ref curArc, position.Clone(), points[1], points[2]);
                }
                else
                {
                    var line = current[index] as Line2d;
                    line.Start = position.Clone();
                }
                Curve2d curLine = index == 0 ? current.Last() : current[index - 1];
                Curve2d curLineCopy = index == 0 ? copy.Last() : copy[index - 1];
                if (curLine is Line2d lastline)
                {
                    lastline.End = position.Clone();
                }
                else if (curLine is Arc2d lastArc)
                {
                    var points = curLineCopy.GetPoints(2);
                    UpdateArc2dByPoints(ref lastArc, points[0], points[1], position.Clone());
                }
            }
        }
        public override void DrawDragGrip(SKCanvas canvas)
        {
            
        }
        /// <summary>
        /// 通过圆上三点求圆心
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        private Vector2 GetCircleCenter(Vector2 a, Vector2 b, Vector2 c)
        {
            double a13 = a.X - c.X;
            double a13_ = a.X + c.X;
            double b13 = a.Y - c.Y;
            double b13_ = a.Y + c.Y;
            double a12 = a.X - b.X;
            double a12_ = a.X + b.X;
            double b12 = a.Y - b.Y;
            double b12_ = a.Y + b.Y;

            double a12b12_2 = a12 * a12_ + b12 * b12_;
            double a13b13_2 = a13 * a13_ + b13 * b13_;

            double a13b12 = 2 * a13 * b12;
            double a12b13 = 2 * a12 * b13;


            if (a12b13 - a13b12 == 0) return new Vector2((b.X + a.X) / 2, (b.Y + a.Y) / 2);
            double af = a12b13 - a13b12;
            double bf = a13b12 - a12b13;
            double az = b13 * a12b12_2 - b12 * a13b13_2;
            double bz = a13 * a12b12_2 - a12 * a13b13_2;
            double x = az / af;
            double y = bz / bf;
            return new Vector2(x, y);
        }

        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
            {

            };
        }
 
        public Tuple<Vector2, Vector2, double> GetCircleBy2PD(Vector2 start, Vector2 End, double degrees)
        {
            double point1X = start.X;
            double point1Y = start.Y;
            double point2X = End.X;
            double point2Y = End.Y;
            double angleDegrees = degrees;

            // 计算中点坐标
            double midPointX = (point1X + point2X) / 2;
            double midPointY = (point1Y + point2Y) / 2;

            // 计算两个点之间的距离
            double distance = Math.Sqrt(Math.Pow(point2X - point1X, 2) + Math.Pow(point2Y - point1Y, 2));

            // 将角度转换为弧度
            double radians = angleDegrees * Math.PI / 180;

            double radius = distance / (2 * Math.Sin(radians / 2));
            //// 计算圆心的偏移量
            //double offsetX = distance * Math.Cos(radians);
            //double offsetY = distance * Math.Sin(radians);
            double centerX = midPointX + radius * Math.Cos(radians / 2);
            double centerY = midPointY + radius * Math.Sin(radians / 2);
            // 计算圆心的坐标
            //double centerX = midPointX + offsetX;
            //double centerY = midPointY + offsetY;
            //double radius = Math.Sqrt(Math.Pow(centerX - point1X, 2) + Math.Pow(centerY - point1Y, 2));


            double dx = point2X - point1X;
            double dy = point2Y - point1Y;

            ///# 将向量差单位化
            double unit_dx = dx / distance;
            double unit_dy = dy / distance;

            ///# 计算圆心坐标
            double h = midPointX + radius * unit_dx;
            double k = midPointY + radius * unit_dy;

            var b = start;
            var a = End;
            var r = radius;

            double c1 = (b.X * b.X - a.X * a.X + b.Y * b.Y - a.Y * a.Y) / (2 * (b.X - a.X));
            double c2 = (b.Y - a.Y) / (b.X - a.X);
            double A = (c2 * c2 + 1);
            double B = (2 * a.X * c2 - 2 * c1 * c2 - 2 * a.Y);
            double C = a.X * a.X - 2 * a.X * c1 + c1 * c1 + a.Y * a.Y - r * r;
            Vector2 center1 = new Vector2();
            Vector2 center2 = new Vector2();

            center1.Y = (-B - Math.Sqrt(B * B - 4 * A * C)) / (2 * A);

            center2.Y = (-B + Math.Sqrt(B * B - 4 * A * C)) / (2 * A);

            center1.X = c1 - c2 * center1.Y;
            center2.X = c1 - c2 * center2.Y;
            return new Tuple<Vector2, Vector2, double>(center1, center2, radius);
        }
        /// <summary>
        /// 切线加终止点画弧线  返回圆心和角度
        /// </summary>
        /// <param name="lineStart"></param>
        /// <param name="lineEnd"></param>
        /// <param name="point"></param>
        /// <returns>  圆心，半径，弧度</returns>
        public Tuple<Vector2, double, double> GetCircleBylinePoint(Vector2 lineStart, Vector2 lineEnd, Vector2 point)
        {
            int tp = IsTopInLine(lineStart, lineEnd, point);
            if (tp == 0)
            {
                return null;//在同一条线上画直线
            }

            double Degrees = GetDegreesByTwoLine(lineStart, lineEnd, lineEnd, point);

            Degrees = 180 - (90 - Degrees) * 2;

            Tuple<Vector2, Vector2, double> cirTuple = GetCircleBy2PD(lineEnd, point, Degrees);
            int tc = IsTopInLine(lineEnd, point, cirTuple.Item1);
            Vector2 circenter;
            if (Degrees < 180)//圆心和线要在同一边 当弧度小于半圆，大于半圆时 ，向量反之  
            {
                if (tc == tp)
                    circenter = cirTuple.Item1;
                else circenter = cirTuple.Item2;
            }
            else
            {
                if (tc != tp)
                    circenter = cirTuple.Item1;
                else circenter = cirTuple.Item2;
            }
            /// 圆心，半径，弧度
            return new Tuple<Vector2, double, double>(circenter, cirTuple.Item3, Degrees);
        }


        /// <summary>
        /// 获取两条线的夹角  
        /// </summary>
        /// <param name="line1start"></param>
        /// <param name="line1End"></param>
        /// <param name="line2start"></param>
        /// <param name="line2End"></param>
        /// <returns></returns>
        public double GetDegreesByTwoLine(Vector2 line1start, Vector2 line1End, Vector2 line2start, Vector2 line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;

            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;

            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;

            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);

            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);

            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }
        public int IsTopInLine(Vector2 line1start, Vector2 line1End, Vector2 point)
        {
            Vector2 S;
            Vector2 E;
            //if (line1start.X < line1End.X)
            //{
            //    S = line1start;
            //    E = line1End;

            //}
            //else
            //   if (line1start.X == line1End.X)
            //{
            //    if (line1start.Y < line1End.Y)
            //    {
            //        S = line1start;
            //        E = line1End;

            //    }
            //    else
            //    {
            //        S = line1End;
            //        E = line1start;


            //    }
            //}
            //else
            //{
            S = line1End;
            E = line1start;

            // }
            double Tmp = (S.Y - E.Y) * point.X + (E.X - S.X) * point.Y + S.X * E.Y - E.X * S.Y;
            if (Tmp == 0)
            {
                return 0;
            }
            if (Tmp > 0)
            {
                return 1;
            }
            else
            { return -1; }
            //                Tmp > 0 在左侧

            //Tmp = 0 在线上

            //Tmp < 0 在右侧
        }
     }
}


